package pw.mcdarc.mc.bython.Asm;


import org.python.objectweb.asm.ClassWriter;
import org.python.objectweb.asm.MethodVisitor;

import static org.python.objectweb.asm.Opcodes.*;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Set;

/*
This file is part of Bython.
Dont remove this header anytime.
Under the Apache2 License.
You can't sell it, repost it, share it without permission.
Date: 八月,27,2016
*/
public class ListenerClassBuilder extends ClassLoader{

    private Set<String> eventList;
    private String name;
    private ClassWriter cw;
    private ClassLoader classLoader;

    public ListenerClassBuilder(String name, Set<String> eventList, ClassLoader classLoader) {
        super(classLoader);
        this.name = name;
        this.eventList = eventList;
        this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        this.classLoader = classLoader;
    }

    public ClassWriter generate() {
        cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, "pw/mcdarc/mc/bython/" + name, null, "java/lang/Object", new String[]{"org/bukkit/event/Listener"});

        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(1,1);
        mv.visitEnd();

        for (String s : eventList) {
            try {
                Class.forName(s);
            } catch (ClassNotFoundException e) {
                continue;
            }
            MethodVisitor emv = cw.visitMethod(ACC_PUBLIC, s.substring(s.lastIndexOf(".") + 1), "(L" + s.replace('.','/') + ";)V", null, null);
            mv.visitCode();
            emv.visitVarInsn(ALOAD, 1);
            emv.visitMethodInsn(INVOKESTATIC,"pw/mcdarc/mc/bython/Event/EventHooker","hook","(Lorg/bukkit/event/Event;)V");
            emv.visitAnnotation("Lorg/bukkit/event/EventHandler;",true).visitEnd();
            emv.visitInsn(RETURN);
            emv.visitMaxs(1,1);
            emv.visitEnd();
        }

        cw.visitEnd();
        return cw;
    }

    public void save(File file){
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(cw.toByteArray());
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public Class loadClass(){
        byte[] classData = cw.toByteArray();
        Class clazz = defineClass("pw.mcdarc.mc.bython." + name, classData, 0, classData.length);
        resolveClass(clazz);
        return clazz;
    }
}
